--------------Crozzzwords--------------
A 4am crack                  2017-11-20
---------------------------------------

Name: Crozzzwords
Genre: educational
Year: 1987
Credits: Methods & Solutions
Publisher: Mindplay, Inc.
Platform: Apple ][+ or later
Media: single-sided 5.25-inch floppy
OS: DOS 3.3
Previous cracks: none

                   ~

               Chapter 0
 In Which Various Automated Tools Fail
          In Interesting Ways


COPYA
  read error on third pass

Locksmith Fast Disk Backup
  unable to read track $14
  copy boots DOS, shows a title screen,
  then hangs with the drive motor on

EDD 4 bit copy (no sync, no count)
  no errors, but copy boots DOS, shows
  a title screen, then displays
  "DISK ERROR 35W" and hangs

Copy ][+ nibble editor
  track $14 is almost entirely sync
  bytes, with the occasional $D5 nibble
  (almost certainly a protection track)

Disk Fixer
  entire disk is standard except T14
  T00,S00 -> DOS 3.3 bootloader
  T01,S09 -> startup program is "POP"
  standard DOS 3.3 disk catalog on T11

Why didn't any of my copies work?
  specially formatted nibble sequence
  on track $14, designed to fool even
  the best bit copiers

Next steps:

  1. Find the protection check that is
     reading track $14
  2. Disable it
  3. Declare victory (*)

(*) go to the gym

                   ~

               Chapter 1
         In Which We Get Lucky


One thing that all protection checks
have in common is they need to access
the disk drive. Since most protection
checks exploit edge cases of how bits
are stored on disk, they need to use
the lowest level access methods to
manipulate those bits manually.

The lowest level way to "read" a disk
is the data latch softswitch address in
the $C0xx range. For slot 6, it's
$C0EC, but to allow disks to boot from
any slot, developers usually use code
like this:

  LDX <slot number x 16>
  LDA $C08C,X

There's nothing that says you have to
use the X-register as the index or the
accumulator as the load register. But
most disks do, out of convention I
suppose (or fear of messing up such
low-level code in subtle ways).

Also, since developers don't actually
want people finding their protection-
related code, they may try to encrypt
it or obfuscate it on disk, in memory,
or both. But eventually, the code must
exist and the code must run, and it
must run on my machine, and I have the
final say on what my machine does or
does not do.

But sometimes you get lucky.

Turning to my trusty Disk Fixer sector
editor, I search the non-working copy
for "BD 8C C0", which is the opcode
sequence for "LDA $C08C,X".

[Disk Fixer]
  ["F"ind]
    ["H"ex]
      ["BD 8C C0"]

                 --v--

------------- DISK SEARCH -------------

$00/$02-$75   $00/$02-$8B   $00/$02-$B4
$00/$02-$E1   $00/$02-$EB   $00/$02-$F6
$00/$03-$2F   $00/$03-$39   $00/$03-$4F
$00/$03-$59   $00/$03-$64   $00/$03-$71
$00/$03-$79   $00/$03-$8B   $00/$03-$95
$00/$06-$A4   $00/$06-$C0   $00/$07-$27
$00/$07-$37   $00/$07-$3C   $1A/$0A-$89
$1A/$0A-$99   $1A/$0A-$B4   $1A/$0A-$C5
$1A/$0A-$CF   $1A/$0A-$DE

                 --^--

The matches on track $00 are part of
DOS 3.3, i.e. not suspicious. But the
cluster of matches on track $1A are
highly suspect.

                   ~

               Chapter 2
      In Which We Find Ourselves
          In Enemy Territory


The protection routine appears to start
at offset $54.

                 --v--

T1A,S0A
----------- DISASSEMBLY MODE ----------
; get boot slot (x16)
0054:A6 2B          LDX   $2B

; save zero page addresses on stack
0056:A5 FD          LDA   $FD
0058:48             PHA
0059:A5 FE          LDA   $FE
005B:48             PHA

; get RWTS parameter table address
005C:20 E3 03       JSR   $03E3
005F:84 FD          STY   $FD
0061:85 FE          STA   $FE

; track $14 -- the mystery track!
0063:A0 04          LDY   #$04
0065:A9 14          LDA   #$14
0067:91 FD          STA   ($FD),Y

; RWTS command = seek
0069:A0 0C          LDY   #$0C
006B:A9 00          LDA   #$00
006D:91 FD          STA   ($FD),Y

; slow down IIgs (has no effect on
; other machines)
006F:AD 36 C0       LDA   $C036
0072:29 7F          AND   #$7F
0074:8D 36 C0       STA   $C036

; disable last line of RWTS that turns
; off the drive motor
0077:A9 60          LDA   #$60
0079:8D 4D BE       STA   $BE4D

; call the RWTS to execute the seek to
; track $14
007C:20 E3 03       JSR   $03E3
007F:20 D9 03       JSR   $03D9

; restore the RWTS code (but the drive
; motor is still on)
0082:A9 BD          LDA   #$BD
0084:8D 4D BE       STA   $BE4D

; if the seek failed for some reason,
; exit
0087:B0 65          BCS   $00EE

; find $D5 nibble
0089:BD 8C C0       LDA   $C08C,X
008C:10 FB          BPL   $0089
008E:48             PHA
008F:68             PLA
0090:C9 D5          CMP   #$D5
0092:D0 F5          BNE   $0089

; initialize a checksum
0094:A0 00          LDY   #$00
0096:8C 6D 47       STY   $476D

; count number of $F7 nibbles before
; another $D5 nibble
0099:BD 8C C0       LDA   $C08C,X
009C:10 FB          BPL   $0099
009E:C9 D5          CMP   #$D5
00A0:F0 0F          BEQ   $00B1
00A2:C9 F7          CMP   #$F7
00A4:D0 01          BNE   $00A7
00A6:C8             INY

; the sum of the nibbles themselves
; constitutes the checksum
00A7:18             CLC
00A8:6D 6D 47       ADC   $476D
00AB:8D 6D 47       STA   $476D
00AE:4C E5 46       JMP   $46E5
00B1:98             TYA
00B2:F0 E0          BEQ   $0094

; skip $FF nibbles
00B4:BD 8C C0       LDA   $C08C,X
00B7:10 FB          BPL   $00B4
00B9:48             PHA
00BA:68             PLA
00BB:C9 FF          CMP   #$FF
00BD:F0 F5          BEQ   $00B4

; if next nibble is $D5, fail
00BF:C9 D5          CMP   #$D5
00C1:F0 35          BEQ   $00F8

; skip several more nibbles
00C3:A0 05          LDY   #$05
00C5:BD 8C C0       LDA   $C08C,X
00C8:10 FB          BPL   $00C5
00CA:48             PHA
00CB:68             PLA
00CC:88             DEY
00CD:D0 F6          BNE   $00C5

; skip $FF nibbles
00CF:BD 8C C0       LDA   $C08C,X
00D2:10 FB          BPL   $00CF
00D4:48             PHA
00D5:68             PLA
00D6:C9 FF          CMP   #$FF
00D8:F0 F5          BEQ   $00CF

; if next nibble is not $D5, fail
00DA:C9 D5          CMP   #$D5
00DC:D0 1A          BNE   $00F8

; skip $FF nibbles
00DE:BD 8C C0       LDA   $C08C,X
00E1:10 FB          BPL   $00DE
00E3:C9 FF          CMP   #$FF
00E5:D0 11          BNE   $00F8

; verify checksum, branch on failure
00E7:AD 6D 47       LDA   $476D
00EA:C9 10          CMP   #$10
00EC:D0 0A          BNE   $00F8

; success path falls through to here --
; turn off drive motor, restore zero
; page, and return to caller gracefully
00EE:BD 88 C0       LDA   $C088,X
00F1:68             PLA
00F2:85 FE          STA   $FE
00F4:68             PLA
00F5:85 FD          STA   $FD
00F7:60             RTS

; all failures lead here --
; wipe memory
00F8:A2 70          LDX   #$70
00FA:A9 A0          LDA   #$A0
00FC:99 FF 48       STA   $48FF,Y
00FF:C8             INY

[continued on T1A,S09]

0000:D0 FA          BNE   $FFFC
0002:EE 4A 47       INC   $474A
0005:CA             DEX
0006:D0 F4          BNE   $FFFC
0008:AD 8A C0       LDA   $C08A

; display encrypted error message
; "DISK ERROR 35W"
000B:20 2F FB       JSR   $FB2F
000E:20 58 FC       JSR   $FC58
0011:A0 0E          LDY   #$0E
0013:B9 6E 47       LDA   $476E,Y
0016:49 BB          EOR   #$BB
0018:99 B4 05       STA   $05B4,Y
001B:88             DEY
001C:10 F5          BPL   $0013
001E:78             SEI

; hang forever
001F:30 FE          BMI   $001F

(This is the behavior I saw on my non-
working EDD bit copy.)

There are no side effects. Replacing
the first byte with an "RTS" will
bypass the entire thing.

T1A,S0A,$54: A6 -> 60

]PR#6
...works...

Quod erat liberandum.

---------------------------------------
A 4am crack                    No. 1534
------------------EOF------------------
